# find_region_by_text 这个函数是截图分析的核心函数 分析过程挺长的.
# 计划一但开动, 就离开鼠标键盘, 全交给程序工作, 那么, K线区域计算一次就可以, 不会有不同的K线区域需要重新计算.
# F12交易窗口不能打开, 否则会报错. 程序自动切窗口时会切错窗口.


import os
import time
import cv2
# print("是否有freetype? ", hasattr(cv2, 'freetype'))  # 输出True表示成功
import subprocess
import numpy as np
print("numpy版本:",np.__version__)  # 确认输出为 1.26.4 或其他 1.x 版本
import pyautogui
import win32gui
import win32con
import pygetwindow as gw
import pytesseract
from PIL import ImageGrab
import argparse
import logging
# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler("stock_analysis.log"),
        logging.StreamHandler()  # 同时输出到控制台
    ]
)

from datetime import datetime
from concurrent.futures import ThreadPoolExecutor
import threading

from shape_judgment.get_stock_id import get_stock_id,get_stock_id_334
from shape_judgment.get_is_delist import is_delist,is_delist_2,is_unlist,is_trade_state_in_downloading
from shape_judgment.write_to_file import write_line_to_file,file_has_content

from shape_judgment.trading_session import trading_session
from shape_judgment.screen_shot_split import split_by_vertical_line, get_key_image
from shape_judgment.set_k_line_state import set_to_daily_k_line, set_to_chip_chart, set_window_pos
from shape_judgment.chip_infomation_extraction import chip_infomation_extraction
from shape_judgment.screen_region_storage import get_screen_clips,get_screen_clips_len
from shape_judgment.judgement_UI import is_have_button_chip,is_have_button_trade
from shape_judgment.no_data_area import NoDataArea
from shape_judgment.pagedown import page_down,set_window_pos_73
from shape_judgment.get_F10_data import module_get_F10_data
from shape_judgment.read_bulletin_board_in_k_line_area import read_bulletin_board
from shape_judgment.right_side_2_main_force import right_side_2_main_force


folder_path = 'data_from_east_money_desktop_app'
current_date = datetime.now() # 获取当前日期
formatted_date = current_date.strftime("%Y-%m-%d_%H")
formatted_date_2 = current_date.strftime("%Y-%m-%d")


class StockAnalyzer:
    def __init__(self, tesseract_path=None, debug=True):
        """初始化股票分析器
        
        Args:
            tesseract_path: Tesseract OCR的安装路径
            debug: 是否启用调试模式
        """
        self.debug = debug
        self.efortune_window = None
        
        # 配置Tesseract OCR路径
        if tesseract_path:
            pytesseract.pytesseract.tesseract_cmd = tesseract_path
        else:
            # 默认路径，根据实际安装位置调整
            default_paths = [
                r'C:\Program Files\Tesseract-OCR\tesseract.exe',
                r'C:\Program Files (x86)\Tesseract-OCR\tesseract.exe'
            ]
            for path in default_paths:
                if os.path.exists(path):
                    pytesseract.pytesseract.tesseract_cmd = path
                    break
            else:
                logging.warning("未找到Tesseract OCR，请确保已安装并指定正确路径")
        
        # 创建调试窗口（如果启用）
        if self.debug:
            window_title = "调试视图#1"

            cv2.namedWindow(window_title.encode("gbk"), cv2.WINDOW_NORMAL)
            cv2.resizeWindow(window_title.encode("gbk"), 1024, 768)
        
        self.trading_session = trading_session()
        self.is_set_to_daily_k_line = False
        self.is_set_to_chip_chart = False
        self.is_set_window_pos_to_sub_module = False
        self.window_pos = (0,0)
        self.is_pressed_end_key_in_first_time = False
        self.no_data_area = NoDataArea()
        self.F10_data = module_get_F10_data()
        
    def find_efortune_window(self):
        """查找东方财富客户端窗口"""
        try:
            # 尝试通过窗口标题查找
            efortune_windows = [w for w in gw.getAllWindows() if "东方财富" in w.title and len(w.title) <= 12]
            
            if not efortune_windows:
                logging.error("未找到东方财富客户端窗口")
                executable_path = 'D:\\Program Files\\eastmoney\\swc8\\stockway.exe'
                # 启动程序
                subprocess.Popen(executable_path)
                logging.info(f"已启动东方财富客户端: {executable_path}")
                # 等待程序初始化（根据实际启动速度调整延迟时间）
                time.sleep(10)  # 等待10秒
                return False
                
            # 选择第一个找到的窗口并激活
            self.efortune_window = efortune_windows[0]
            if not self.efortune_window.isActive:
                self.efortune_window.activate()
                time.sleep(1)  # 等待窗口激活
            
            self.read_bulletin_board = read_bulletin_board(self.efortune_window) # 初始化 read_bulletin_board 公告获取模块
            self.right_side_2_main_force = right_side_2_main_force(self.efortune_window) # 初始化 right_side_2_main_force 右侧边栏2主力分析模块
            
            logging.info(f"找到东方财富窗口: {self.efortune_window.title}")
            logging.info(f"窗口位置: 左上角({self.efortune_window.left}, {self.efortune_window.top}), "
                         f"大小: {self.efortune_window.width}x{self.efortune_window.height}")
            return True
        except Exception as e:
            logging.error(f"查找东方财富窗口时出错: {str(e)}")
            raise e
            return False

    # 用于调试, 把图片存到硬盘上
    def save_frame_to_image(self,frame, output_path):
        """
        将OpenCV格式的frame保存为图片文件
        :param frame: OpenCV处理后的图像（BGR格式，由cv2.cvtColor转换得到）
        :param output_path: 输出图片路径（需包含文件名和格式，如"stock_screenshot.png"）
        """
        if frame is None:
            raise ValueError("输入的frame为空，无法保存")
        
        # 校验图像格式（必须是2D或3D数组，符合图像格式）
        if len(frame.shape) not in (2, 3):
            raise ValueError(f"frame格式错误，应为图像数组，实际shape: {frame.shape}")
        
        # 使用OpenCV保存图片
        # 支持的格式由output_path的后缀决定（如.png、.jpg、.jpeg等）
        success = cv2.imwrite(output_path, frame)
        
        if not success:
            raise IOError(f"保存图片失败，请检查路径是否有效：{output_path}")
        print(f"图片已保存至：{output_path}")
    

    # 用于还原最小化状态
    def is_window_minimized(self,window):
        """判断窗口是否处于最小化状态"""
        # 对于Windows系统，使用win32gui获取更准确的窗口状态
        try:
            hwnd = window._hWnd  # 获取窗口句柄
            return win32gui.IsIconic(hwnd)
        except:
            # 跨平台备选方案：最小化窗口通常位置在屏幕外或尺寸为0
            screen_width, screen_height = pyautogui.size()
            x, y = window.left, window.top
            width, height = window.width, window.height
            # 检查窗口是否在屏幕可视区域外或尺寸过小
            return (x < -100 or y < -100 or width < 10 or height < 10)
        
    def capture_window(self):
        """捕获东方财富窗口的截图"""
        if not self.efortune_window:
            while not self.find_efortune_window():
                continue
                
        try:
            # 还原最小化的状态:
            # print(f"# 154 窗口状态:{self.efortune_window.isMaximized}  {self.efortune_window.isActive}  {self.efortune_window.visible}  {self.is_window_minimized(self.efortune_window)} ")
            if(self.is_window_minimized(self.efortune_window)):
                print("# 203")
                hwnd = self.efortune_window._hWnd# self.get_window_handle("东方财富终端")
                print(" 调用 SetForegroundWindow ")
                win32gui.SetForegroundWindow(hwnd)
                time.sleep(0.3)
                print("调用 showWindow")
                win32gui.ShowWindow(hwnd, win32con.SW_RESTORE)
                result = win32gui.ShowWindow(hwnd, win32con.SW_RESTORE)
                if result:
                    print("通过激活后还原成功")

            # 获取窗口位置和大小
            x, y = self.efortune_window.left, self.efortune_window.top
            self.window_pos = (x,y)
            width, height = self.efortune_window.width, self.efortune_window.height
            
            # 截取窗口区域
            screenshot = ImageGrab.grab(bbox=(x, y, x + width, y + height))
            # 转换为OpenCV格式 (BGR)
            frame = cv2.cvtColor(np.array(screenshot), cv2.COLOR_RGB2BGR)
            # self.save_frame_to_image(frame,"frame_for_debug.png")
            return frame
        except Exception as e:
            logging.error(f"截图时出错: {str(e)}")
            return None
    
    def resize_to_same_width(self,img, target_width):
        """将图像调整为目标宽度，高度按比例缩放"""
        h, w = img.shape[:2]
        if w == 0:
            return img
        scale = target_width / w
        new_h = int(h * scale)
        return cv2.resize(img, (target_width, new_h))
    
    # 垂直排列图片
    def stack_images_vertically(self,images):
        """
        垂直拼接多个图像（宽度统一，垂直排列）
        :param images: 图像列表（BGR格式）
        :return: 拼接后的大图
        """
        if not images:
            return None
        
        # 统一所有图像的宽度（以最宽的图像为标准）
        max_width = max(img.shape[1] for img in images)
        # 调整所有图像到相同宽度
        resized_images = [self.resize_to_same_width(img, max_width) for img in images]
        
        # 垂直拼接（使用numpy的vstack）
        stacked = np.vstack(resized_images)
        return stacked









    last_time = 0
    retry_times = 0 # 重试次数, 出现右侧边栏数据已经读取出来了, 图表区还在读取.
    retry_times_F10 = 0
    DOWNLOADING_TIMES_LIMIT = 10
    downloading_times = 0
    # 获取计算出来的数据并绘制
    def process_frame(self, frame):
        """处理单帧图像，提取并分析K线区域"""
        if frame is None:
            return None
        
        # 复制原始帧用于调试显示
        debug_frame = frame.copy()
        
        # # 调用各个分析程序 2025-10-01
        # result1 = self.trading_session.calculate(frame,debug_frame)

        # time1 = time.time()
        print("\n# 240 与上一次的时间差:",time.time()-self.last_time) 
        self.last_time = time.time()
        bool_have_result2 = False
        if(0 == get_screen_clips_len()):
            result2 = get_key_image(frame) # 取得关键图像
        result_clips = get_screen_clips(frame)
        for i in result_clips:
            print(f"# 246 {i}")
        result2 = [result_clips["筹码区"]]

        
        stock_id = get_stock_id( result_clips["股票名称与价格"]) 
        # logging.info(f" # 264 分析步骤:第一次取股票ID:{stock_id}") 
        if stock_id is None:
            stock_id = get_stock_id_334(frame)
            # logging.info(f" # 264 分析步骤:第二次取股票ID:{stock_id}") 
        
        bool_is_trade_state_downloading = is_trade_state_in_downloading(result_clips["交易状态后半栏"])
        if(bool_is_trade_state_downloading):
            # 还在下载数据, 等待
            # print("# 247 still downloading data, wait...")
            logging.info(f" # 269 分析步骤:还在下载数据, 等待") 
            time.sleep(0.6)
            self.downloading_times -= 1
            if(self.downloading_times < 0):
                # 下载数据超时, 目前是限制6秒
                self.downloading_times = self.DOWNLOADING_TIMES_LIMIT
                self.no_data_area.record_none_data_state()
                page_down(stock_id,self.no_data_area,frame)
            return debug_frame
        bool_is_have_button_trade = is_have_button_trade(result_clips["右侧边栏2的顶部按钮区"])
        # print(f"# 272 交易按钮:{bool_is_have_button_trade}")
        if(not bool_is_have_button_trade):
            # 没有交易按钮, 跳过
            # print("# 272 没有交易按钮, 跳过")
            self.no_data_area.record_none_data_state()
            page_down(stock_id,self.no_data_area,frame)
            logging.info(f" # 289 分析步骤:没有交易按钮 下一页") 
            return debug_frame

        bool_is_delist = is_delist_2(result_clips["交易状态后半栏"])
        bool_is_unlisted = is_unlist(result_clips["交易状态后半栏"])
        # print("# 251 是否已退市:",bool_is_delist,"\t是否未上市:",bool_is_unlisted)

        # return debug_frame # 至此, 用时0.05秒
        if(bool_is_delist or bool_is_unlisted):
            self.no_data_area.record_none_data_state()
            page_down(stock_id,self.no_data_area,frame)
            time.sleep(0.1)
            logging.info(f" # 289 分析步骤:退市或未上市 下一页") 
            return debug_frame
        
        bool_have_result3 = False
        result3 = []
        if len(result2):
            bool_have_result2 = True
            result3 = chip_infomation_extraction(result2[0]) # 取筹码数据
            # print(f"# 240 result3:{result3}")
        if(len(result3) and result3[0][1]!=0):
            bool_have_result3 = True
            logging.info(f" # 307 分析步骤:bool_have_result3 = True  StockID: {stock_id}") 
        # return debug_frame # 至此, 用时0.28秒 由于有个tesseract函数, 耗时是没办法的.
        # time2 = time.time()
        # print(f"# 236 获取关键数据用时:{time2-time1}")

        # 重试:
        if(not bool_have_result3 and self.retry_times>0):
            self.retry_times-=1
            time.sleep(0.1)
            logging.info(f" # 307 分析步骤:重试") 
            return debug_frame
        elif not bool_have_result3:
            print("# 308 已重试3次, 放弃")
            logging.info(f" # 311 分析步骤:已重试3次, 放弃") 

        bool_have_result_K_1 = False # 图表区数据1
        # cv2.imwrite("k_debug_333.png", result_clips["最大图表区"])
        # 右侧边栏2:
        bool_have_right_side_2_main_force = False
        result_main_force = self.right_side_2_main_force.get()
        if(result_main_force is not None):
            bool_have_right_side_2_main_force = True
        if not bool_have_right_side_2_main_force and self.retry_times>0:
            self.retry_times-=1
            time.sleep(0.1)
            logging.info(f" # 348 分析步骤:重试 主力流入数据的获取")
            return debug_frame
        elif not bool_have_right_side_2_main_force:
            logging.info(f"# 351 主力流入数据的获取 已重试3次, 放弃")


        # 分析公告:        
        time.sleep(1) # TODO 之后需要通过分析右侧边栏的数据来判断延迟多少
        result_k_1_bool_have_dividend =  self.read_bulletin_board.read_bulletin_board_in_k_line_area(result_clips["K线图表区"])
        if(result_k_1_bool_have_dividend):
            file_path = os.path.join(folder_path, 'dividend_' + formatted_date + '.txt')
            write_line_to_file(file_path,f"{stock_id[1:]}")
            # raise Exception(f"# 344 取到分红股:{stock_id[1:]}")
            
        # raise Exception("# 334 调试完") # 换由模块内部作出中断

        logging.info(f" # 312 分析步骤:已取得数据")

        bool_have_result_4 = False
        if(bool_have_result2 and bool_have_result3):
            result4 = self.F10_data.get()
            if result4 is None and self.retry_times_F10>0:
                self.retry_times_F10-=1
                result4 = self.F10_data.get()
            if result4 != None:
                bool_have_result_4 = True
                logging.info(f" # 337 {stock_id} result4:{result4}")
            else:
                time.sleep(0.1)
                logging.info(f" # 344 分析步骤4:重试")
                return debug_frame # 暂不跳转下一页.
        
        if(bool_have_result2 and bool_have_result3 and bool_have_result_4):
            print(f"# 249 已取得该股所有数据 记录并翻页")
            # print(f"result3:{result3}")
            obj_prepare_to_write = {
                "有效像素点数目":0,
                "获利比率":0,
                "筹码集中度":0
            }
            # 遍历记录2:
            for i in range(len(result3)):
                if(result3[i][0] == '筹码有效像素点数目:'):
                    obj_prepare_to_write["有效像素点数目"] = result3[i][1]
                if(result3[i][0] == '获利比率'):
                    obj_prepare_to_write["获利比率"] = result3[i][1]
                if(result3[i][0] == '筹码集中度'):
                    obj_prepare_to_write["筹码集中度"] = result3[i][1]
            # print("写文件之前输出:",obj_prepare_to_write)
            print(f"# 257 stock_id:{stock_id}")
            # 定义要保存的文件名
            file_path = os.path.join(folder_path, 'chip_' + formatted_date + '.csv')
            write_line_to_file(file_path,
                               stock_id
                               +","+str(obj_prepare_to_write["有效像素点数目"])
                               +","+str(obj_prepare_to_write["获利比率"])
                               +","+str(obj_prepare_to_write["筹码集中度"]))
            if bool_have_right_side_2_main_force:
                file_path = os.path.join(folder_path, 'main_force_' + formatted_date + '.csv')
                print(f"# 407 result_main_force:{result_main_force}")
                str_main_force_data = stock_id
                for main_force_data in result_main_force:
                    str_main_force_data+=","+main_force_data[1]
                write_line_to_file(file_path,str_main_force_data)
            
            # BEGIN F10
            file_path_F10_1 = os.path.join(folder_path, 'F10_pageone_' + formatted_date_2 + '.csv')
            is_was_a_file = file_has_content(file_path_F10_1)
            len_result4 = len(result4)
            if not is_was_a_file:
                str_table_header = "股票ID,"
                for i in range(len_result4):
                    str_table_header += result4[i][0]+","
                write_line_to_file(file_path_F10_1,str_table_header)
            # 写信息到文件中:
            str_content = stock_id+","
            for i in range(len_result4):
                str_content += str(result4[i][1])+","
            write_line_to_file(file_path_F10_1,str_content)
            # END F10


            page_down(stock_id,self.no_data_area,frame)
            self.no_data_area.record_still_have_data_area(stock_id)
            self.retry_times = 3
            self.retry_times_F10 = 3
            self.downloading_times = self.DOWNLOADING_TIMES_LIMIT
            time.sleep(0.1)
        else:
            print("# 337 该股无数据")
            bool_have_button_chip = is_have_button_chip(result_clips["筹码按钮所在的菜单栏"])
            if(False == bool_have_button_chip):
                # 开发过程中, 记录调试信息 ",无筹码按钮_无筹码数据"
                # file_path = os.path.join(folder_path, 'chip_' + formatted_date + '.csv')
                # write_line_to_file(file_path,
                #                    stock_id+",无筹码按钮_无筹码数据")
                self.no_data_area.record_none_data_state()
                page_down(stock_id,self.no_data_area,frame)
                self.retry_times = 3
                self.downloading_times = self.DOWNLOADING_TIMES_LIMIT
                time.sleep(0.1)
            else:
                # 有筹码按钮, 却没有数据
                file_path = os.path.join(folder_path, 'chip_' + formatted_date + '.csv')
                # write_line_to_file(file_path,
                #                    stock_id+",有筹码按钮_但无筹码数据")
                self.no_data_area.record_none_data_state()
                page_down(stock_id,self.no_data_area,frame)
                self.retry_times = 3
                self.retry_times_F10 = 3
                self.downloading_times = self.DOWNLOADING_TIMES_LIMIT
                time.sleep(0.1)
        # print(f"# 263 result1:{result1}")
        # else:
        #     if self.top_left_button is not None:
        #         print(f"# ERR 427     {len(self.top_left_button)}")
        return debug_frame









    def run(self, interval=2):
        """运行主分析循环
        
        Args:
            interval: 分析间隔时间（秒）
        """
        logging.info("开始股票分析程序...")
        print("按 'q' 键退出程序")
        
        try:
            while True:
                # 捕获窗口图像
                # time_1 = time.time()
                frame = self.capture_window()
                # time_2 = time.time()
                # print(f"# 320 获取帧用时:{time_2-time_1}")
                if frame is None:
                    # print(f"sleep {interval}s")
                    time.sleep(interval)
                    continue
                
                if self.is_set_window_pos_to_sub_module == False:
                    set_window_pos(self.window_pos[0],self.window_pos[1])
                    set_window_pos_73(self.window_pos[0],self.window_pos[1])
                    self.is_set_window_pos_to_sub_module = True
                
                # 切换到日K线界面:
                if self.is_set_to_daily_k_line == False:
                    self.is_set_to_daily_k_line = set_to_daily_k_line(frame)
                    continue
                # 切换出筹码图表:
                if self.is_set_to_chip_chart == False:
                    self.is_set_to_chip_chart = set_to_chip_chart(frame)
                    continue
                if self.is_pressed_end_key_in_first_time == False:
                    pyautogui.press('end')
                    time.sleep(0.5) # 等数据刷新再截图一次, 不然会是旧的数据
                    frame = self.capture_window()
                    self.is_pressed_end_key_in_first_time = True
                if self.F10_data.init_done == False:
                    self.F10_data.init_2(self.efortune_window)

                # 处理图像
                # time1 = time.time()
                processed_frame = self.process_frame(frame)
                # time2 = time.time()
                # print(f"# 236 获取关键数据用时:{time2-time1}")
                
                # 显示调试窗口
                # time3 = time.time()
                if self.debug and processed_frame is not None:
                    window_title1 = "调试视图#1".encode("gbk")
                    cv2.imshow(window_title1, processed_frame)
                    cv2.resizeWindow(window_title1, 1024, 768)
                    # 检查按键，按q退出
                    if cv2.waitKey(1) & 0xFF == ord('q'):
                        logging.info("用户请求退出程序")
                        break
                # time4 = time.time()
                # print(f"# 263 显示调试用时:{time4-time3}") # 263 显示调试用时:0.010177850723266602
                
                # 等待下一次分析
                # print(f"sleep {interval}s")
                time.sleep(interval)
                
        except KeyboardInterrupt:
            logging.info("用户中断程序")
        finally:
            logging.info("程序结束")
            cv2.destroyAllWindows()

if __name__ == "__main__":
    # 解析命令行参数
    parser = argparse.ArgumentParser(description='东方财富股票K线分析工具')
    parser.add_argument('--tesseract', type=str, help='Tesseract OCR的安装路径')
    parser.add_argument('--interval', type=int, default=0.002, help='分析间隔时间（秒）')
    parser.add_argument('--no-debug', action='store_true', help='禁用调试窗口')
    args = parser.parse_args()
    
    if args.tesseract is None:
        args.tesseract = "D:\\Program Files\\Tesseract-OCR\\tesseract.exe"

    # 创建分析器实例
    analyzer = StockAnalyzer(
        tesseract_path=args.tesseract,
        debug=not args.no_debug
    )
    
    # 运行分析程序
    analyzer.run(interval=args.interval)


# 2025-08-25:
# 1. 解决子窗口问题, 关掉子窗口后, 新生成的子窗口过大. [completed]
# 2. 解决调试窗口中, OpenCV绘制出来的中文字符全是问号的问题.[STOP]难以解决,依赖库会有冲突问题.
#    需要安装带扩展的OpenCV, 不然就没法使用freetype
#    pip install opencv-contrib-python
#    [STOP]难以解决,依赖库会有冲突问题.

#2025-08-27 [completed]:
# 需解决识别失败的问题: 明明有0.00%这几个字, 但就是识别不到.
#    1. 使用图像比对的方式(模板匹配), 因为文字样式,颜色(灰度),大小,绝对是一样的.
#    2. 匹配最右边的一个"0.00%", 因为"0.00%"在K线图的右侧
#    3. 阈值设置为0.99, 之前的0.8是绝对不行的, 会匹配到10.05%这样的数字.0.99这个阈值没发现有问题.
#        最右边与匹配度最高目前没法同时作为筛选条件, 因为对图像识别不熟悉, 不知道这阈值会不会有波动,之前玩原神时, 有时会识别错误,有不稳定的情况. 另一方面,需要一个类似评分系统的算法,比较复杂
#        所以, 这方面难以做到完美. 再试试, 精度不够用再说.

# 2025-08-29:
# 取K线区域, 并截图存在内存中
#    1. 取集合竞价正上方的两个按钮位置 [completed] 
#    如此, 取到的图是包括成交量的.
#    如何去掉成交量区域, 或者如何取成交量与集合竞价? 上下两取有一个空行, 这个空行内没有网格. 可以通过像素点逐个判断.

# 2025-08-30 一定要用线程, 否则窗口卡死, 不能拖动.
#    

# 2025-08-31 
# find_top_left_of_k_line_area.py 代码复制一下就有了, 很冗余, 等下再解决. 先把程序跑通.
#     1. 导入函数 [completed]
#     2. 设计一个英文名指代这个事务 "find_top_left_of_k_line_area" [completed]
#     3. 写子线程函数, 在子线程调用所导入的函数 [completed]
#     4. 写子线程回调函数, 回调时设置任务状态为false [completed]
#        创建一个专用的存储区给左上角的识别结果 [completed]
#     5. 创建对应的处理线程 [completed]
#     6. 实时绘制图像识别的结果 [completed]

# 2025-09-01 取K线区的下方坐标

# 2025-09-02 截取K线图区域

# 2025-09-04 切分集合竞价的价格走势并切开盘后交易

# 2025-09-10 逐个记录穿头破脚数据, 记录头与脚的高度.
#    1. 穿头远比破脚高, 才叫穿头
#    2. 破脚远比穿头高, 才叫破脚
#    3. 做一个模块, 用于写入一行数据写到文件中, 如果文件不存在, 就创建一个.
#        打开文件, 写完马上关闭, 不用等程序结束再写,比较有抗风险能力.
#

# 2025-10-02 日K线的分析模块
#    窗口区域的切分
#    由于有某个线段有个意外的缺口, 所以算法上分为横竖两种切法. 图表区域之外, 有(60,60,60)这种颜色的竖线.
# TODO 自动做胜率统计没法做的一个点: 持仓时间不固定. 有可能几年都在股底. 若是真要暴力运算个几年, 那买入的点是非常之多. 一只股票会有多次持仓监控, 参数的组合又是指数级上升.
#    更大的暴力运算: 从现在开始慢慢收录各个参数, 解决掉之前做模拟时参数很单一的问题, 然后, 再用收集来的历史数据做一次模拟.

# 2025-10-08 
# 自动按[筹码]按钮  筹码的显示风格现在还用不到, 不用那么细
# 固定裁剪区域, 减少运算量, 从一秒多减少到0.7秒.
# [completed] 解决股票ID识别问题: 文字的坐标因为1这个数字识别有误. 另外, 六个数字识别成七个数字, 说明tesseract算法不可信任.
# TODO 自动按还原最大化的按钮, 以减少窗口大小, 以减少运算量.

# 2025-10-09
# 104767 深圳2004这是个债券, 在取得交易状态后, 还是取不到筹码数据. 要是能判断它没有K线就好了.
#   但是, 出现了"# 249 已取得该股所有数据 记录并翻页", 这个日志是错的
#   这个日志之前还有个"!!!!    ERR 142 没取得模板位置" 这个报错在: chip_infomation_extraction.py
#   设置一个状态 state_none_data_area = 0 # 0: 有数据的区域, 1: 记录了无数据区的开始,等待无数据区 0: 记录了无数据区的结束 # 开始与结束的股票ID都是有数据的. 这就需要把pagedowm放到分支中.
#       当从无数据区出来时, 记录头尾, stockid_none_data_area_start="", stockid_none_data_area_end=""
#       写到文件中, 成两列, 需做成一个模块 , 这方面还是有点复杂的.

# 2025-10-10
# 038036 界面布局就不一样, 侧边栏少了一个, 没有交易按钮.

# 2025-10-11
# 400264 明明没有Data, 却被none_data_area.py识别为有数据. 调用了record_still_have_data_area # 24 `400263 
# 会卡翻页, 需要鼠标滚轮向下滑一下才能继续. 这个问题正在解决, 试试解决了没


# 2025-10-26
# TODO: 分析出K线的横坐标是可行的, 每根K线是3像素宽, K线之间间隔1像素, K线的像素点只有两种颜色 红(255,92,92), 绿(0,255,255)
# TODO: 鼠标移上公告图标, 会出现一种没有标题的弹窗, 目前没办法只截取这种弹窗. 所以又只能截大区域分析. 从鼠标所在处去找, 就能找到(0,0,0)这样的像素点, 然后走格子找出弹窗的黑色边框, 就可以取得弹窗.
#       至于弹窗中的文字怎么识别, 当然用图像识别比较快.
#       TODO 取得公告后, 就可以通过网页取得分红的数值.
# TODO: F10 有一个页面[分红融资],这里有股息率这个指标.
# 

